STM32第七章-脉冲宽度调制
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度进行控制。
我们假定定时器工作在向上计数 PWM模式,且当 CNT
STM32F429 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。直接开搞,来看一下定时器的分类,这是F4的定时器分配图
通道是什么,我们换个说法,通道=路=引脚,这样是不是好理解一点,也就是说TIM2有4路定时器。TIM5也有4路,TIM3也有4路,TIM4也有4路。为什么要这么多路呢?
比如我们要产生8路周期,占空比都不同的PWM信号输出,那我们可以选TIM2的 CH1/CH2/CH3/CH4 还有TIM3 的CH1,CH2,CH3,CH4 这8路进行输出,需要这么多路,就是为了可以输出/输入 更多的信号。比如你用小舵机做一个小机器人就需要很多的定时器对应很多的通道也就是对应很多引脚。输出的信号分别是哪些管脚呢。很明显对F4来说就是
TIM5的CH1/CH2/CH3/CH4对应PH10/PH11/PH12/PIO这4个管脚。
捕获/比较使能寄存器(TIMx_CCER)
捕获/比较寄存器(TIMx_CCR1~4)
刹车和死区寄存器(TIMx_BDTR)这个寄存器一般在高级定时器中使用,就是TIM1和TIM8。如果你没用到这两个定时器就不要管这个寄存器了。脉冲宽度调制模式可以生成一个信号,该信号频率由 TIMx_ARR 寄存器值决定,其占空比则由 TIMx_CCRx 寄存器值决定。
寄存器讲解
捕获/比较模式寄存器
捕获/比较使能寄存器
见名知意,当然是使能TIM3定时器的啊。使CC4E置位为1就可以了。
捕获/比较寄存器
程序代码配置
我们文本的例子是定时器3的通道3,对应PB0管脚。
1.开启TIM3时钟,配置 PB0
要使用 TIM3,我们必须先开启 TIM3的时钟,这点相信大家看了这么多代码,应该明白了。这里我们还要配置 PB0 为复用输出(当然还要使能 GPIOB的时钟),这是因为 TIM3_CH3通道将使用 PB0的复用功能作为输出,我们配置 PB0为复用输出,才可以实现 TIM3_CH3的 PWM 经过 PB0输出。
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //使能GPIO外设时钟
//设置该引脚为复用输出功能,输出TIM3 CH3的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
2.设置 TIM3的ARR和PSC
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 100;
TIM_TimeBaseStructure.TIM_Prescaler =360-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
3.使能TIM3的CH3输出
接下来,我们要设置 TIM3_CH3为 PWM 模式,我们要通过配置 TIM3_CCMR2的相关位来控制 TIM3_CH3 的模式。在库函数中,PWM 通道设置是通过函数 TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道 3,所以使用的函数是 TIM_OC3Init()。这里的结构体我就不多少了,自己看一下就可以明白,对于普通定时器我们只需要设置下面这四个参数就可以了。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 500;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
③配置占空比:占空比=配置占空比的值/TIM_TImeBaseStructure.TIM_Period,这里的占空比为50/100=50%
50%的占空比那么波形也一定是一半高一半低对吧,一会我们仿真看一看。
4使能TIM3
所有的都配置完了,最后能一下TIM3。
TIM_Cmd(TIM3, ENABLE);//使能TIM3
5.使能TIM3的预装载寄存器
使能TIM3在CCR3上的预装载寄存器
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); ////使能TIM3在CCR3上的预装载寄存器,即TIM3_CCR3的预装载值在更新事件到来时才能被传送至当前寄存器中。
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3在ARR上的预装载寄存器 (影子寄存器)
这里我们来讲一下影子寄存器:
1.有影子寄存器的有3个:分频寄存器PSC,自动重装载寄存器 ARR,自动捕获CCRx(x是对应的通道),注意,PSC,ARR,CCRx不是影子寄存器,而是它们对应的"预装载寄存器"
2、影子寄存器才是真正起作用的寄存器,但是ST没有提供这个寄存器出来,只是提供出与之相对应的预装载寄存器,分别为"PSC,ARR,CCRx"
3、我们用户能接触到,能修改或读取的都是预装载寄存器,ST只是把它们开放出来(影子寄存器并没有开放给用户),其实就是ARR寄存器,如:TIM3->ARR
4、从预装载寄存器ARR传送到影子寄存器,有两种方式,一种是立刻更新,一种是等触发事件之后更新;这两种方式主要取决于寄存器TIMx->CR1中的"APRE"位;
APRE=0,当ARR值被修改时,同时马上更新影子寄存器的值;APRE=1,当ARR值被修改时,必须在下一次事件发生后才能更新影子寄存器的值;
5、怎么样马上立刻更改影子寄存器的值,而不是下一个事件;方法如下:
将ARPE=0,TIM_ARRPreloadConfig(TIM3, DISABLE);
在ARPE=1,TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_ARRPreloadConfig设置为DISABLE 和ENABLE的问题,他的作用只是允许或禁止在定时器工作时向ARR的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值。在开始初始化的时候你已经把
汇总一下代码:
void TIM3_PWM_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//使能GPIO外设时钟
//设置该引脚为复用输出功能,输出TIM3 CH3的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 100; //输出PWM波形的频率=定时器的输入频率/TIM_TImeBaseStructure.TIM_Period,200 000Hz/100=2000Hz,即0.5ms一个周期
TIM_TimeBaseStructure.TIM_Prescaler =360-1;//不分频 输入频率=APB1时钟/(预分频系数+1)=72 000 000Hz/360=200 000Hz =200K
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 50; //占空比=配置占空比的值/TIM_TImeBaseStructure.TIM_Period,500/1000=50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH3预装载使能
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3在ARR上的预装载寄存器 (影子寄存器)
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
6.主函数的编写
主函数就很简单,一个while函数就可以解决。
int main(void)
{
SystemInit ();
TIM3_PWM_Init();
while(1)
{
}
}
TB6612引脚分配:
VM PWMA--------->TIM3_CH3(PBO)
VCC AIN2--------->GPIOB_12
GND AIN1--------->GPIOB_13
AO1 STBY--------->GPIOB_14
AO2 BIN1--------->GPIOB_15
BO2 BIN2--------->GPIOA_12
BO1 PWMB--------->TIM3_CH4(PB1)
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
int main(void)
{
u16 i=0;
SystemInit ();
TIM3_PWM_Init();
while(1)
{
i++;
TIM_SetCompare3(TIM3,i);//定时器3的通道3
if(i==100) i=0;
}
}
如果觉得文章对你有帮助,欢迎转发、分享给你的朋友,感谢您的支持!
如需转载请联系我!